using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Northwoods.Go;
using Workflows.Components.Rules;

namespace Rules.Diagram
{
    /// <summary>
    /// diagram view that holds document
    /// </summary>
    public class RuleView : GoView
    {
        /// <summary>
        /// 
        /// </summary>
        public RuleView()
        {
            // have GoView.CreateLink make a copy of a RuleLink, instead of the standard GoLink
            this.NewLinkPrototype = new RuleLink();
            // initialize the RuleDoc
            this.Doc.Initialize();
            // now keep track of undo/redo
            this.Doc.UndoManager = new GoUndoManager();
            this.AllowMove = true;
        }

        /// <summary>
        /// by default, the Document is a RuleDoc
        /// </summary>
        /// <returns></returns>
        public override GoDocument CreateDocument()
        {
            return new RuleDoc();
        }

        /// <summary>
        ///  a convenience property
        /// </summary>
        public RuleDoc Doc
        {
            get { return this.Document as RuleDoc; }
        }


        // produce a translucent version of the node that will be dropped
        protected override GoObject GetExternalDragImage(DragEventArgs evt)
        {
            IDataObject data = evt.Data;
            //Object treeNodeObj = data.GetData(typeof(TreeNode));
            //if(treeNodeObj !=null && treeNodeObj is TreeNode)
            //{
            //    object tag = ((TreeNode) treeNodeObj).Tag;
            //    if (tag.GetType() == typeof(DeclarativeRuleCondition) || tag.GetType().IsSubclassOf(typeof(RuleCondition)))
            //    {
            //        RuleCondition condition = (RuleCondition)tag;
            //        RuleNode ruleNode = new RuleNode(condition.RuleNodeType);
            //        GoImage goImg = new GoImage();
            //        goImg.Image = condition.Img;
            //        ruleNode.Image = goImg;
            //        ruleNode.Shadowed = false;
            //        GoShape back = (GoShape)ruleNode.Background;
            //        SolidBrush b = back.Brush as SolidBrush;
            //        if (b != null)
            //        {
            //            ruleNode.Brush = new SolidBrush(Color.FromArgb(64, b.Color));
            //        }
            //        return ruleNode;
            //    }
            //    else if (tag.GetType() == typeof(RuleAction) || tag.GetType().IsSubclassOf(typeof(RuleAction)))
            //    {
            //        RuleAction action = (RuleAction)tag;
            //        RuleNode ruleNode = new RuleNode(action.RuleNodeType);
            //        ruleNode.Image.Image = action.Img;
            //        ruleNode.Shadowed = false;
            //        GoShape back = (GoShape)ruleNode.Background;
            //        SolidBrush b = back.Brush as SolidBrush;
            //        if (b != null)
            //        {
            //            ruleNode.Brush = new SolidBrush(Color.FromArgb(64, b.Color));
            //        }
            //        return ruleNode;
            //    }
            //    else if (tag.GetType() == typeof(RuleEffect) || tag.GetType().IsSubclassOf(typeof(RuleEffect)))
            //    {
            //        RuleEffect effect = (RuleEffect)tag;
            //        RuleNode ruleNode = new RuleNode(effect.RuleNodeType);
            //        ruleNode.Image.Image = effect.Img;
            //        ruleNode.Shadowed = false;
            //        GoShape back = (GoShape)ruleNode.Background;
            //        SolidBrush b = back.Brush as SolidBrush;
            //        if (b != null)
            //        {
            //            ruleNode.Brush = new SolidBrush(Color.FromArgb(64, b.Color));
            //        }
            //        return ruleNode;
            //    }
            //    else if (tag.GetType() == typeof(RuleOutput) || tag.GetType().IsSubclassOf(typeof(RuleOutput)))
            //    {
            //        RuleOutput output = (RuleOutput)tag;
            //        RuleNode ruleNode = new RuleNode(output.RuleNodeType);
            //        ruleNode.Image.Image = output.Img;
            //        ruleNode.Shadowed = false;
            //        GoShape back = (GoShape)ruleNode.Background;
            //        SolidBrush b = back.Brush as SolidBrush;
            //        if (b != null)
            //        {
            //            ruleNode.Brush = new SolidBrush(Color.FromArgb(64, b.Color));
            //        }
            //        return ruleNode;
            //    }
            //}


            Object treenodeobj = data.GetData(typeof(TreeNode));
            if (treenodeobj != null && treenodeobj is TreeNode)
            {
                TreeNode treenode = (TreeNode)treenodeobj;
                RuleNode tag = treenode.Tag as RuleNode;
                if (tag != null && tag.Background is GoShape)
                {
                    RuleNode copy = (RuleNode)tag.Copy();
                    copy.Shadowed = false;
                    GoShape back = (GoShape)copy.Background;
                    SolidBrush b = back.Brush as SolidBrush;
                    if (b != null)
                    {
                        copy.Brush = new SolidBrush(Color.FromArgb(64, b.Color));
                    }
                    return copy;
                }
            }
            return base.GetExternalDragImage(evt);
        }

        // while dragging, highlight any objects we pass over, and set the
        // DragEventArgs.Effect appropriately
        protected override void DoExternalDrag(DragEventArgs evt)
        {
            base.DoExternalDrag(evt);  // also do standard behavior
            this.AllowMove = true;
            GoObject over = PickObject(true, false, this.LastInput.DocPoint, false);
            if (over != null && (over.TopLevelObject is RuleLink))
            {
                evt.Effect = DragDropEffects.Copy;
                RuleLink link = (RuleLink)over.TopLevelObject;
                this.Highlit = link;
                return;
            }
            else if (over != null && (over.TopLevelObject is RuleNode))
            {
                RuleNode node = (RuleNode)over.TopLevelObject;
                if (node.Kind != RuleNodeType.Start)
                {
                    evt.Effect = DragDropEffects.Copy;
                    this.Highlit = node;
                    return;
                }
            }
            evt.Effect = DragDropEffects.None;
            this.Highlit = null;
        }

        /// <summary>
        /// keep track of last highlit object
        /// </summary>
        public IHighlit Highlit
        {
            get { return myHighlit; }
            set
            {
                IHighlit old = myHighlit;
                if (old != value)
                {
                    if (old != null) old.Highlit = false;
                    myHighlit = value;
                    if (value != null) value.Highlit = true;
                }
            }
        }
        private IHighlit myHighlit = null;

        // when a drop occurs from a TreeView, depending on what object the drop happens,
        // call InsertNodeBeforeNode or InsertNodeOnLink within a transaction
        protected override IGoCollection DoExternalDrop(DragEventArgs evt)
        {
            this.Highlit = null;
            IDataObject data = evt.Data;
            Object treenodeobj = data.GetData(typeof(TreeNode));
            if (treenodeobj != null && treenodeobj is TreeNode)
            {
                TreeNode treenode = (TreeNode)treenodeobj;
                Point screenPnt = new Point(evt.X, evt.Y);
                Point viewPnt = PointToClient(screenPnt);
                PointF docPnt = ConvertViewToDoc(viewPnt);
                RuleNode tag = treenode.Tag as RuleNode;
                if (tag == null) return null;
                GoObject over = PickObject(true, false, docPnt, false);
                if (over == null) return null;
                RuleLink link = over.TopLevelObject as RuleLink;
                if (link != null)
                {
                    StartTransaction();
                    RuleNodeDataBase nodeData = (RuleNodeDataBase) tag.UserObject;
                    RuleNodeDataBase ruleNodeData = nodeData.Clone();
                    RuleNode ruleNode = new RuleNode(ruleNodeData.RuleNodeType);
                    ruleNode.ToolTipText = ruleNodeData.Description;
                    ruleNode.UserObject = ruleNodeData;
                    ruleNode.Image.Image = ruleNodeData.Img;

                    RuleNode node = this.Document.AddCopy(ruleNode, docPnt) as RuleNode;
                    this.Doc.InsertNodeOnLink(node, link);
                    //if (this.AutoLayout) this.Doc.Layout();
                    this.Selection.Select(node);
                    FinishTransaction("Insert from TreeView");
                    return this.Selection;
                }
                else
                {
                    RuleNode oldnode = over.TopLevelObject as RuleNode;
                    if (oldnode != null)
                    {
                        StartTransaction();
                        RuleNode newnode = this.Document.AddCopy(tag, docPnt) as RuleNode;
                        this.Doc.InsertNodeBeforeNode(newnode, oldnode);
                        //if (this.AutoLayout) this.Doc.Layout();
                        this.Selection.Select(newnode);
                        FinishTransaction("Insert from TreeView");
                        return this.Selection;
                    }
                }
                return null;
            }
            else
            {
                return base.DoExternalDrop(evt);
            }
        }

        //public virtual bool AutoLayout
        //{
        //    get { return !this.AllowMove; }
        //}

        // don't just delete selected nodes (and their links), but all Conditional node branches;
        // then patch together the nodes left behind after the deletion
        protected override void OnSelectionDeleting(System.ComponentModel.CancelEventArgs evt)
        {
            base.OnSelectionDeleting(evt);
            foreach (GoObject obj in this.Selection.CopyArray())
            {
                RuleNode node = obj as RuleNode;
                if (node != null)
                {
                    this.Doc.RemoveNode(node);
                }
            }
        }

        // after a deletion, re-layout
        //protected override void OnSelectionDeleted(EventArgs evt) {
        //  base.OnSelectionDeleted(evt);
        //  //if (this.AutoLayout) this.Doc.Layout();
        //}
    }
}
